package GUI;

import edu.uci.ics.jung.graph.ArchetypeVertex;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.decorators.DefaultToolTipFunction;
import edu.uci.ics.jung.graph.decorators.EdgeShape;
import edu.uci.ics.jung.graph.decorators.VertexStringer;
import edu.uci.ics.jung.graph.impl.SparseGraph;
import edu.uci.ics.jung.visualization.AbstractLayout;
import edu.uci.ics.jung.visualization.DefaultSettableVertexLocationFunction;
import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
import edu.uci.ics.jung.visualization.PluggableRenderer;
import edu.uci.ics.jung.visualization.ShapePickSupport;
import edu.uci.ics.jung.visualization.StaticLayout;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
import edu.uci.ics.jung.visualization.control.EditingModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ScalingControl;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.AbstractAction;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;

/**
 * Graficzny edytor grafu
 * 
 * @author Piotrek
 * 
 */
public class GraphEditor extends JApplet {

    private Graph graph = new SparseGraph();
    private AbstractLayout layout;
    /**
     * renderer grafu
     */
    private VisualizationViewer vv;
    private DefaultSettableVertexLocationFunction vertexLocations;
    private JPanel controls;
    private Container content;
    private PluggableRenderer pr;

    /**
     * Konstruktor GrapdEditor tworzy prosty interfejs
     * do rysowania grafów
     */
    public GraphEditor() {
        paint();
    }

    /**
     * Konstruktor GraphEditor wyświetlający wejściowy graf do edycji.
     * @param graph wczytany graf
     */
    public GraphEditor(Graph graph) {
        this.graph = graph;
        paint();

    }

    /**
     * Zwraca aktualnie narysowany graf.
     * @return narysowany graf
     */
    public Graph getGraph() {
        return graph;
    }

    /**
     * GraphEditor main do testowania
     * @return edytor grafów z menu
     */
    public static GraphEditor make() {
        final GraphEditor graphEditor = new GraphEditor();

        JMenu menu = new JMenu("Opcje");
        menu.add(new AbstractAction("Zapisz jako..") {

            public void actionPerformed(ActionEvent e) {
                JFileChooser chooser = new JFileChooser();
                // zapisz jako menu-filtr
                chooser.addChoosableFileFilter(new JPGFilter());
                chooser.addChoosableFileFilter(new PNFFilter());
                chooser.addChoosableFileFilter(new GMLFilter());
                chooser.setAcceptAllFileFilterUsed(false);
                int option = chooser.showSaveDialog(graphEditor);
                if (option == JFileChooser.APPROVE_OPTION) {
                    File file = chooser.getSelectedFile();
                    // wybór rozszerzenia pliku
                    // jpg
                    if (chooser.getFileFilter().toString().equalsIgnoreCase(Utils.jpg)) {
                        GraphIO.writeJPEGImage(file, graphEditor.vv);
                    // pnf
                    } else if (chooser.getFileFilter().toString().equalsIgnoreCase(Utils.pnf)) {
                        GraphIO.writeGraphPNF(graphEditor.graph, file.getPath());
                    // gml
                    } else if (chooser.getFileFilter().toString().equalsIgnoreCase(Utils.gml)) {
                        GraphIO.writeGraphGML(graphEditor.graph, file.getPath());
                    }
                }
            }
        });


        menu.add(new AbstractAction("Wczytaj..") {

            public void actionPerformed(ActionEvent e) {

                JFileChooser chooser = new JFileChooser();
                // wczytaj menu-filtr
                chooser.addChoosableFileFilter(new PNFFilter());
                chooser.addChoosableFileFilter(new GMLFilter());
                chooser.setAcceptAllFileFilterUsed(false);
                int option = chooser.showOpenDialog(graphEditor);
                if (option == JFileChooser.APPROVE_OPTION) {
                    File file = chooser.getSelectedFile();
                    if (chooser.getFileFilter().toString().equalsIgnoreCase(Utils.pnf)) {
                        graphEditor.graph = GraphIO.readGraphPNF(file.getPath());
                    } else if (chooser.getFileFilter().toString().equalsIgnoreCase(Utils.gml)) {
                        graphEditor.graph = GraphIO.readGraphGML(file.getPath());
                    } else {
                        return;
                    }
                    graphEditor.vv.stop();
                    graphEditor.layout = new StaticLayout(graphEditor.graph);
                    graphEditor.vv.setGraphLayout(new StaticLayout(graphEditor.graph), false);
                    graphEditor.vv.restart();
                }

            }
        });

        menu.add(new AbstractAction("Drukuj") {

            public void actionPerformed(ActionEvent e) {
                GraphIO.print(graphEditor.vv);
            }
        });

        JMenuBar menuBar = new JMenuBar();
        menuBar.add(menu);
        graphEditor.controls.add(menuBar, BorderLayout.EAST);
        return graphEditor;
    }

    private void paint() {
        // ustawienia precyzji dla początkowych położeń wierzchołków
        vertexLocations = new DefaultSettableVertexLocationFunction();

        pr = new PluggableRenderer();
        layout = new StaticLayout(graph);
        layout.initialize(new Dimension(600, 600), vertexLocations);

        vv = new VisualizationViewer(layout, pr);
        vv.setBackground(Color.white);
        vv.setPickSupport(new ShapePickSupport());
        pr.setEdgeShapeFunction(new EdgeShape.QuadCurve());
        pr.setVertexStringer(new VertexStringer() {

            public String getLabel(ArchetypeVertex v) {
                return v.toString();
            }
        });

        vv.setToolTipFunction(new DefaultToolTipFunction());

        content = getContentPane();
        final GraphZoomScrollPane panel = new GraphZoomScrollPane(vv);
        content.add(panel);
        final EditingModalGraphMouse graphMouse = new EditingModalGraphMouse();

        // EditingGraphMouse przesyła event'y 
        // do vertexLocations aby ustalić położenia utworzonych wierzchołków      
        graphMouse.setVertexLocations(vertexLocations);
        vv.setGraphMouse(graphMouse);
        graphMouse.add(new GraphEditorPopupMouse(vertexLocations));
        graphMouse.setMode(ModalGraphMouse.Mode.EDITING);

        final ScalingControl scaler = new CrossoverScalingControl();
        JButton plus = new JButton("+");
        plus.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                scaler.scale(vv, 1.1f, vv.getCenter());
            }
        });
        JButton minus = new JButton("-");
        minus.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                scaler.scale(vv, 1 / 1.1f, vv.getCenter());
            }
        });
        controls = new JPanel();
        controls.add(plus);
        controls.add(minus);

        JComboBox modeBox = graphMouse.getModeComboBox();
        controls.add(modeBox);
        content.add(controls, BorderLayout.SOUTH);
    }
}
